#include <iostream>
#include <stdio.h>
#include <string>
#include <stdexcept>
#include <stdlib.h>
#include "types/DateTime.h"

#include "factory/Fabrica.h"
#include "interfaces/IControladorRecurso.h"
#include "interfaces/IControladorUsuario.h"

using namespace std;

int main(){

	Fabrica * factory;
	factory = Fabrica::getInstancia();
	IControladorRecurso * controladorRecursos;
	IControladorUsuario * controladorUsuarios;
	controladorRecursos = factory->getControllerRecurso();
	controladorUsuarios = factory->getControllerUsuario();
	factory->setControladorRecurso((ControladorUsuario*)controladorUsuarios);
	factory->setControladorUsuario((ControladorRecurso*)controladorRecursos);
	


	int comando1;
	int comando2;
	int comando3;
	cout << "Menu de opciones" << endl;
	cout << endl;
	cout << "1 - Opciones de Recursos" << endl;
	cout << "2 - Opciones de Usuarios" << endl;
	cout << "0 - Salir" << endl;
	cout << endl;
	cout << "> ";
	cin >> comando1;
    if (comando1!=0){
		do{
            switch(comando1){
            //Opciones de Recursos
			case 1:{
				cout << "Opciones de Recursos" << endl;
				cout << endl;
				cout << "1 - Crear recurso" << endl;
				cout << "2 - Modificar Archivo" << endl;
				cout << "3 - Ingresar Comentario" << endl;
				cout << "4 - Ver informacion de un archivo" << endl;
				cout << "5 - Ver informacion de una Carpeta" << endl;
				cout << "0 - Salir al menu anterior" << endl;
				cout << endl;
				cout << "> ";
				cin >> comando2;
				if (comando2!=0)
					do{
						switch(comando2){
						//Crear Recurso
						case 1:{
							try{
								controladorUsuarios->noHayUsuarios();
							}
							catch(std::out_of_range& e){
								 cout << e.what();
							     cout << endl;
								 comando2 = 0;
								 break;
							}
							string nombre;
							string descripcion;
							string tipo;
							string userCreador;
							string ruta;
							bool error = true;
							cout << "Opciones de Creacion" << endl;
							cout << endl;
							cout << "1 - Crear archivo" << endl;
							cout << "2 - Crear carpeta" << endl;
							cout << "0 - Cancelar" << endl;
							cout << endl;
							cout << "> ";
							cin >> comando3;
							if(comando3!=0){
                                do{
                                switch (comando3){
                                case 1:{
                                    tipo="archivo";
                                    cout << "Ingrese el nombre del archivo:" << endl;
                                    cout << endl;
                                    cout << "> ";
                                    cin >> nombre;
                                    cout << "Ingrese la descripcion del archivo:" << endl;
                                    cout << endl;
                                    cout << "> ";
                                    cin >> descripcion;
                                    while(error){
                                    try {
                                    	controladorRecursos->crearRecurso(nombre, descripcion, tipo);
										error = false;
                                        }
                                    catch (std::out_of_range& e){
                                        cout << e.what();
										cout << endl;
										cout << "Ingrese el nombre del archivo:" << endl;
                                        cout << endl;
                                        cout << "> ";
                                        cin >> nombre;
                                        }
									}
									error = true;
                                    cout << "Indique el nombre del usuario creador del archivo:" << endl;
                                    cout << endl;
									controladorUsuarios->imprimirNicknamesUsuarios();
									cout << endl;
                                    cout << "> ";
                                    cin >> userCreador;
									while(error){
									try{
										controladorUsuarios->esUsuarioDelSistema(userCreador);
										error = false;
									}
									 catch (std::out_of_range& e){
                                         cout << e.what();
										 cout << endl;
										 cout << "Indique el nombre del usuario creador del archivo:" << endl;
                                         cout << endl;
                                         cout << "> ";
                                         cin >> userCreador;
                                        }
									}
									error = true;
                                    try {
                                    	controladorRecursos->indicarCreador(userCreador);
                                    }
                                    catch (std::out_of_range& e){
                                        cout << e.what();
                                        }
									cout << endl;
									cout << "Ingrese la ruta del archivo separado por barras:" << endl;
                                    cout << endl;
                                    cout << "> ";
                                    cin >> ruta;
									while(error){
									 try {
										 controladorRecursos->indicarDestino(ruta);
										 error = false;
                                    }
                                    catch (std::out_of_range& e){
                                        cout << e.what();
										cout << endl;
									    cout << "Ingrese la ruta del archivo separado por barras:" << endl;
                                        cout << endl;
                                        cout << "> ";
                                        cin >> ruta;
                                        }
									}
									cout << endl;
                                    cout << "Archivo creado exitosamente." << endl;
                                    break;
                                }//case 1
                                case 2:{
                                    tipo="carpeta";
                                    cout << "Ingrese el nombre de la carpeta:" << endl;
                                    cout << endl;
                                    cout << "> ";
                                    cin >> nombre;
                                    cout << "Ingrese la descripcion de la carpeta:" << endl;
                                    cout << endl;
                                    cout << "> ";
                                    cin >> descripcion;
                                     while(error){
                                    try {
                                    	controladorRecursos->crearRecurso(nombre, descripcion, tipo);
										error = false;
                                        }
                                    catch (std::out_of_range& e){
                                        cout << e.what();
										cout << endl;
										cout << "Ingrese el nombre de la carpeta:" << endl;
                                        cout << endl;
                                        cout << "> ";
                                        cin >> nombre;
                                        }
									}
									error = true;
                                    cout << "Indique el nombre del usuario creador de la carpeta:" << endl;
                                    cout << endl;
									controladorUsuarios->imprimirNicknamesUsuarios();
									cout << endl;
                                    cout << "> ";
                                    cin >> userCreador;
									while(error){
									try{
										controladorUsuarios->esUsuarioDelSistema(userCreador);
										error = false;
									}
									 catch (std::out_of_range& e){
                                         cout << e.what();
										 cout << endl;
										 cout << "Indique el nombre del usuario creador de la carpeta:" << endl;
                                         cout << endl;
                                         cout << "> ";
                                         cin >> userCreador;
                                        }
									}
									error = true;
                                    try {
                                    	controladorRecursos->indicarCreador(userCreador);
                                    }
                                    catch (std::out_of_range& e){
                                        cout << e.what();
                                        }
									cout << endl;
									cout << "Ingrese la ruta de la carpeta separado por barras:" << endl;
                                    cout << endl;
                                    cout << "> ";
                                    cin >> ruta;
									while(error){
									 try {
										 controladorRecursos->indicarDestino(ruta);
										 error = false;
                                    }
                                    catch (std::out_of_range& e){
                                        cout << e.what();
										cout << endl;
									    cout << "Ingrese la ruta de la carpeta separado por barras:" << endl;
                                        cout << endl;
                                        cout << "> ";
                                        cin >> ruta;
                                        }
									}
									cout << endl;
                                    cout << "Carpeta creada exitosamente." << endl;
                                    break;
                                }//case 2
                                }//switch comando3
                                cout << "Opciones de Creacion" << endl;
                                cout << endl;
                                cout << "1 - Crear archivo" << endl;
                                cout << "2 - Crear carpeta" << endl;
                                cout << "0 - Cancelar" << endl;
                                cout << endl;
                                cout << "> ";
                                cin >> comando3;
                                }while(comando3!=0);
							}//if
							break;
						/* Caso de Uso - Modificar Archivo */
						}
						case 2:{
							string autor;
							bool modificar, encontrado, tienePermisos = false;
							string nombreArchivo;
							string ubicacionArchivo;
							string nuevaDescripcion;
							cout << "Usuarios del sistema:" << endl;
							cout << endl;
							/****************************************/
							try {

								//modificarArchivoExistente();
								controladorUsuarios->imprimirUsuariosSistema();

								}
							catch (std::out_of_range& e){
								cout << e.what();
								}
							/***************************************/
							cout << "Seleccione el autor de la modificacion:" << endl;
							cout << endl;
							cout << "> ";
							cin >> autor;
							/***************************************/
							try {
								modificar = controladorUsuarios->elegirAutorModificacionArchivo(autor);
							}
							catch (std::out_of_range& e){
								cout << e.what();
							}

							if (modificar){

								/***************************************/
								cout << "Seleccione el archivo a modificar:" << endl;
								cout << endl;

								controladorRecursos->imprimirArchivosSistema();

								cout << "> ";
								cin >> nombreArchivo;
								cout << "> ";
								cin >> ubicacionArchivo;

								tienePermisos = controladorUsuarios->permisosModificacion(autor, nombreArchivo, ubicacionArchivo);

								if (tienePermisos){
									/***************************************/
									try {

										encontrado = controladorRecursos->elegirArchivoAModificar(nombreArchivo, ubicacionArchivo);

									}catch (std::out_of_range& e){
										cout << e.what();
									}

									if (encontrado){
										/***************************************/
										cout << "Ingrese la nueva descripcion del archivo:" << endl;
										cout << endl;
										cout << "> ";
										cin >> nuevaDescripcion;
										/***************************************/
										try {

											controladorRecursos->ingresarNuevaDescripcionArchivo(nombreArchivo, ubicacionArchivo,  nuevaDescripcion);

											string accion = "modificacion";
											controladorUsuarios->notificarUsuarios(controladorRecursos, accion);

										}catch (std::out_of_range& e){
											cout << e.what();
										}
										/***************************************/
									}else{
										cout << "No existe archivo con nombre " << nombreArchivo << " para la ruta " << ubicacionArchivo << "." << endl;
									}
								}else{
									cout << "Permisos insuficientes." << endl;
								}

							}else{
								cout << "No existe usuario con el nickname ingresado." << endl;
							}

							break;
						}
						/* Caso de Uso - Ingresar Comentario */
						case 3:{
							string ruta;
							string usr;
							string texto;
							string nombreArchivo;
							cout << "Ingrese la ruta del archivo a comentar. Se desplegaran los comentarios del mismo." << endl;
							cout << endl;
							cout << "> ";
							cin >> ruta;
							cout << "Ingrese el nombre del archivo a comentar. Se desplegaran los comentarios del mismo." << endl;
							cout << endl;
							cout << "> ";
							cin >> nombreArchivo;
							/***************************************/
							try {
								controladorRecursos->registrarNuevoComentario(ruta,nombreArchivo);
								}
							catch (std::out_of_range& e){
								cout << e.what();
								}
							/***************************************/
							cout << "Opciones de comentario:" << endl;
							cout << endl;
							cout << "1- Realizar un nuevo comentario." << endl;
							cout << "2- Responder sobre un comentario ya existente." << endl;
							cout << "> ";
							cin >> comando3;
							switch (comando3){
							case 1:{
								/***************************************/
								try {
									controladorRecursos->ingresarNuevoComentario();
									}
								catch (std::out_of_range& e){
									cout << e.what();
								}
								/***************************************/
								break;
							}
							case 2:{
								int idComentario;
								cout << "Ingrese ID del comentario a responder:" << endl;
								cout << endl;
								cout << "> ";
								cin >> idComentario;
								/***************************************/
								try {
									controladorRecursos->ingresarComentarioRespuesta(idComentario);
									}
								catch (std::out_of_range& e){
									cout << e.what();
									}
								/***************************************/
								break;
							}
							}
							cout << "Ingrese usuario:" << endl;
							cout << endl;
							cout << "> ";
							cin >> usr;
							cout << "Ingrese texto del comentario:" << endl;
							cout << endl;
							cout << "> ";
							cin >> texto;
							/***************************************/
							try {
								controladorRecursos->ingresarUsuarioYTexto(usr,texto);
								}
							catch (std::out_of_range& e){
								cout << e.what();
								}
							/***************************************/
							break;
						}
						//Ver Informacion de un archivo
						case 4:{
							int idArchivo;
							cout << "A continuacion se despliegan los archivos del sistema:" << endl;
							cout << endl;
							/***************************************
							try {
								verInformacionArchivo();
								}
							catch (std::out_of_range& e){
								cout << e.what();
								}
							***************************************/
							cout << "Seleccione el ID del archivo:" << endl;
							cout << endl;
							cout << "> ";
							cin >> idArchivo;
							/***************************************
							try {
								elegirArchivoSistema(idArchivo);
								}
							catch (std::out_of_range& e){
								cout << e.what();
								}
							***************************************/
							break;
						}
						//Ver Informacion de una carpeta
						case 5:{
							string rutaCarpeta;
							cout << "A continuacion se despliegan las carpetas del sistema:" << endl;
							cout << endl;
							/***************************************
							try {
								verInformacionCarpeta();
								}
							catch (std::out_of_range& e){
								cout << e.what();
								}
							***************************************/
							cout << "Seleccione la ruta de la carpeta:" << endl;
							cout << endl;
							cout << "> ";
							cin >> rutaCarpeta;
							/***************************************
							try {
								elegirCarpetaSistema(rutaCarpeta);
								}
							catch (std::out_of_range& e){
								cout << e.what();
								}
							***************************************/
							break;
                            }
                        }
                        cout << endl;
                        cout << "> ";
                        cin >> comando2;
                    }while(comando2!=0);
                else
                    break;
                break;
            }
			//Opciones de Usuarios
			case 2:{
				cout << "Opciones de Usuario:" << endl;
				cout << endl;
				cout << "1 - Alta de Usuario." << endl;
				cout << "2 - Iniciar colaborador en raiz." << endl;
				cout << "3 - Agregar colaborador." << endl;
				cout << "4 - Ver informacion de un Usuario." << endl;
				cout << "0 - Salir al menu anterior." << endl;
				cout << endl;
				cout << "> ";
				cin >> comando2;
				if (comando2!=0)
					do{
						switch(comando2){

						/* Caso de uso: Alta de usuario */
						case 1:{
							string nombreUsuario;
							string sexo;
							bool ingresarDatosUsuario = true;
							bool error = true;
							DateTime fecha;
							cout << "Ingrese el nombre del usuario a crear:" << endl;
							cout << endl;
							cout << "> ";
							cin >> nombreUsuario;
							while(error)
							{
                            try{

                                ingresarDatosUsuario = controladorUsuarios->ingresarNickName(nombreUsuario);
								error = false;

                            }catch (std::out_of_range& e){
                                    cout << e.what();
									cout << endl;
									cout << "Ingrese el nombre del usuario a crear:" << endl;
							        cout << endl;
							        cout << "> ";
							        cin >> nombreUsuario;
                            }
							}
                            if (ingresarDatosUsuario){

									cout << "Ingrese sexo del usuario a crear:" << endl;
									cout << endl;
									cout << "> ";
									cin >> sexo;
									cout << "\nIngrese la fecha de nacimiento del usuario a crear en el formato YYYY/MM/DD:" << endl;
									cout << endl;
									cout << "> ";
									double YY;
									double MM;
									double DD;
									char c;
									cin >> YY;
									cin >> c;
									cin >> MM;
									cin >> c;
									cin >> DD;
									fecha = DateTime(YY, MM, DD);

                                try{
                                        controladorUsuarios->ingresarDatosUsuario(sexo, fecha);
                                }catch (std::out_of_range& e){
                                    cout << e.what();
                                }

                            }else{
                                cout << "\nYa existe un usuario registrado en el sistema con el nickname ingresado." << endl;
                            }


							/***************************************/

						break;
						}
						/* Caso de uso: Iniciar colaborador en raiz */
						case 2:{
							string nickName;
							bool registrar = false;
							cout << "\nA continuacion se listan los usuarios del sistema:"<< endl;
							cout << endl;
							/***************************************/
							try {

								controladorUsuarios->imprimirUsuariosSistema();

							}catch (std::out_of_range& e){
								cout << e.what();
							}
							/***************************************/
							cout << "\nIngrese el nickname del usuario a iniciar como colaborador en la raiz:" << endl;
							cout << endl;
							cin >> nickName;
							/***************************************/

							if (!controladorUsuarios->esColaborador(nickName)){
								try {

									registrar = controladorUsuarios->registrarUsuarioColaboradorRaiz(controladorRecursos, nickName);

								}catch (std::out_of_range& e){
								cout << e.what();
								}

								if (registrar){
									cout << "\nEl usuario " << nickName << " se agrego correctamente como colaborador en la raiz." << endl;
								}else{
									cout << "\nNo existe un usuario en el sistema con nickname: "<< nickName << "." << endl;
								}
							}else{
								cout << "\nEl usuario " << nickName << " ya ha sido agregado como colaborador en la raiz." << endl;
							}
						break;
						}
						/* Caso de Uso - Agregar Colaborador */
						case 3:{
							string nickName;
							string nombreCarpeta, rutaCarpeta;
							bool registrar, existeCarpeta, exito = false;
							cout << "\nA continuacion se listan los usuarios del sistema:" << endl;
							/***************************************/
							try {

								controladorUsuarios->imprimirUsuariosSistema();

							}catch (std::out_of_range& e){
								cout << e.what();
							}
							/***************************************/
							cout << "\nIngrese el nickname del usuario a ingresar. Se listaran las carpetas del usuario ingresado: " << endl;
							cout << endl;
							cout << "> ";
							cin >> nickName;
							/***************************************/
							try {

								registrar = controladorUsuarios->registrarUsuarioColaborador(nickName);

							}catch (std::out_of_range& e){
								cout << e.what();
							}

							if (registrar){
								/***************************************/
								cout << "\nIngrese el nombre y la ruta de la carpeta a colaborar. Se desplegaran los usuarios del sistema." << endl;
								cout << endl;
								cout << "> ";
								cin >> nombreCarpeta;
								cout << "> ";
								cin >> rutaCarpeta;

								/***************************************/
								try {

									existeCarpeta = controladorRecursos->elegirCarpetaAColaborar(nickName, nombreCarpeta, rutaCarpeta);

								}catch (std::out_of_range& e){
									cout << e.what();
								}

								if (existeCarpeta){
									/***************************************/
									cout << "\nSeleccione el usuario a agregar como colaborador de la carpeta seleccionada:" << endl;
									cout << endl;

									controladorUsuarios->imprimirUsuariosSistema();

									cout << "> ";
									cin >> nickName;
									/***************************************/
									try {

										exito = controladorUsuarios->elegirUsuarioColaborador(controladorRecursos, nickName);

										if(exito){
											cout << "\nEl usuario " << nickName << " ha sido agregado como colaborador sobre la carpeta " << nombreCarpeta << "." << endl;
										}else{
											cout << "\nNo existe usuario de nickname: " << nickName << endl;
										}
									}catch (std::out_of_range& e){
										cout << e.what();
									}
									/***************************************/
								}else{
									cout << "No existe carpeta para la ruta ingresada." << endl;
								}
							}else{
								cout << "No existe usuario de nickname: " << nickName << endl;
							}
							break;
						}
						//Ver informacion de un usuario
						case 4:{
							string nickName;
							cout << "A continuacion se desplegaran los usuarios del sistema: " << endl;
							/***************************************/
							try {
								controladorUsuarios->imprimirUsuariosSistema();
								}
							catch (std::out_of_range& e){
								cout << e.what();
								}
							/***************************************/
							cout << "Ingrese el nickname del usuario: " << endl;
							cout << endl;
							cout << "> ";
							cin >> nickName;
							try {
							    controladorUsuarios->elegirUsuarioSistema(nickName);
								}
							catch (std::out_of_range& e){
								cout << e.what();
								}
                            try {
							    controladorRecursos->imprimirHistorialUsuario(nickName);
								}
							catch (std::out_of_range& e){
								cout << e.what();
								}
							break;
						}
						}
                        cout << endl;
                        cout << "> ";
                        cin >> comando2;
                    }while(comando2!=0);
                else
                    break;
                break;
                }
            }
            cout << "Menu de opciones" << endl;
            cout << endl;
            cout << "1 - Opciones de Recursos" << endl;
            cout << "2 - Opciones de Usuarios" << endl;
            cout << "0 - Salir" << endl;
            cout << endl;
            cout << "> ";
            cin >> comando1;
        }while(comando1!=0);
    }
    return 0;
}

